--[[ 编码: WMS-100-03 名称: PLC-PLCStateChange 作者:HAN 入口函数: PLCStateChange 功能说明: 新兴项目中的线体PLC状态发生变化后会通过这个可编程接口告诉WMS系统 发送过来的数据是一个Json包,格式如下: {"device_code":"D001","comm_code":"1001_STUS","value":[1,1,0,1008,0,0,0,100],"time":"2023-09-05 16:16:00"} 分别表示下面这些状态 (1) 线体状态 0 空闲 1 运行 2 急停 state (2) 光电信号 0 无框 1 有框 with_tray 有托盘 (3) 任务号 0~65535 task_no (4) 目标地址 1008 线体编号 target_addr (5) 线体信号 0 无动作 1=允许出框 2=允许进框 signal (6) 任务状态反馈 0 无任务 1=出框完成 2=进框完成 task_state (7) 外形检测 目前没有用 (8) 重量 目前没有用 变更记录: --]] wms_dev = require( "wms_devcomm" ) wms_eq = require( "wms_equipment" ) wms_cntr= require( "wms_container" ) wms_wh = require( "wms_wh" ) -- 创建入库作业 -- location 货位 cntr_code 容器编码 -- device_code 输送线线体设备编码 local function create_warehousing_operation( strLuaDEID, device_code, str_loc_code, cntr_code ) local location local nRet -- 判断一下是否已经存在托盘号 = cntr_code 的未完成作业,如果已经存在不需要继续创建作业 -- 因为 PLC 这边有 60s 强制通知策略,因此加一个防护 nRet, strRetInfo = wms_cntr.InOperation( strLuaDEID, cntr_code ) if (nRet ~= 0) then lua.Error( strLuaDEID, debug.getinfo(1), "WMS_Container_InOperation失败! " .. strRetInfo) end if (strRetInfo == 'yes') then return end -- 获取货位信息 nRet, location = wms_wh.Location_GetInfo( strLuaDEID, str_loc_code ) if ( nRet ~= 0 ) then lua.Error( strLuaDEID, debug.getinfo(1), 'wms_wh.Location_GetInfo 失败!'..location ) end -- 创建作业 local operation = m3.AllocObject(strLuaDEID,"Operation") operation.start_wh_code = location.wh_code operation.start_area_code = location.area_code operation.start_loc_code = location.code operation.op_type = wms_base.Get_nConst(strLuaDEID, "作业类型-入库") operation.op_def_name = "成品入库" operation.cntr_code = cntr_code operation.ext_data = device_code -- 注意:把线体的编码保存在扩展属性中,在生成任务的时候会用到 nRet, strRetInfo = m3.CreateDataObj( strLuaDEID, operation ) if ( nRet ~= 0 ) then lua.Error( strLuaDEID, debug.getinfo(1), '创建【作业】失败!'..strRetInfo ) end end -- 创建设备动作队列 -- device_code -- 输送线设备号 task_code -- 任务号 action_code -- 动作码 action -- 动作 line_seg_code -- 线体段号 local function Create_MQAction( strLuaDEID, device_code, task_code, action_code, action, line_seg_code ) if ( device_code == nil or device_code == '' ) then lua.Error( strLuaDEID, debug.getinfo(1), '创建【设备动作队列】失败! 设备号必须有值' ) end -- step2 获取车辆基本信息 local eq nRet, eq = wms_eq.Equipment_GetInfo( strLuaDEID, device_code ) if ( nRet ~= 0 ) then lua.Error( strLuaDEID, debug.getinfo(1), eq ) end -- 如果车辆没定义工厂标识返回错误 if ( eq.factory == '') then strErr = "设备编号='"..strForkliftNo.."' 没定义工厂标识!" lua.Error( strLuaDEID, debug.getinfo(1), strErr ) end -- step3 判断当前车辆的动作码是否已经在队列中(MQ_EQAction) local mq_eq_action = m3.AllocObject(strLuaDEID,"MQ_EQAction") mq_eq_action.task_code = task_code mq_eq_action.eq_code = device_code mq_eq_action.action_code = action_code mq_eq_action.action = action mq_eq_action.data = line_seg_code -- 线体这里已经存在设备动作记录就不需要继续进行处理 local strCondition = "N_ACTION_CODE = "..action_code.." AND S_EQ_CODE = '"..mq_eq_action.eq_code.."' AND ( N_B_STATE = 0 OR N_B_STATE = 1 ) " strCondition = strCondition.." AND S_DATA = '"..line_seg_code.."'" nRet, strRetInfo = mobox.existThisData( strLuaDEID, "MQ_EQAction", strCondition ) if ( nRet ~= 0 ) then lua.Error( strLuaDEID, debug.getinfo(1), strRetInfo ) end -- 如果该车辆编码的动作已经在队列,返回,不做处理 if ( strRetInfo == "yes" ) then return end -- step4 把车辆动作写入队列 mq_eq_action.factory = eq.factory mq_eq_action.eq_type = eq.type mq_eq_action.eq_type_name = eq.name nRet, strRetInfo = m3.CreateDataObj( strLuaDEID, mq_eq_action ) if ( nRet ~= 0 ) then lua.Error( strLuaDEID, debug.getinfo(1), strRetInfo ) end end -- 主函数 -- PLC 状态变化后脚本处理程序 function PLCStateChange ( strLuaDEID ) local nRet, strRetInfo local input_datajson = {} -- step1 获取接口中的Data nRet, input_datajson = m3.GetSysDataJson( strLuaDEID ) if ( nRet ~=0 ) then lua.Error( strLuaDEID, debug.getinfo(1), "PLCStateChange 无法获取数据包!"..input_datajson ) end local device_code = lua.Get_StrAttrValue( input_datajson.device_code ) local comm_code = lua.Get_StrAttrValue( input_datajson.comm_code ) local value = input_datajson.value -- step2: 如果线体无框就返回 if ( value[wms_base.Get_nConst(strLuaDEID,"输送线-光电信号")] ~= 1 ) then return end -- step3 检查从PLC传入的数据进行合法性判断 if ( device_code ~= "S7_Line_01") then lua.Warning( strLuaDEID, debug.getinfo(1), "PLC传入的设备号 device_code 不正确,目前只是接收 S7_Line_01 设备的信号接入!" ) return end if ( comm_code == '' ) then lua.Warning( strLuaDEID, debug.getinfo(1), "PLC传入的设备通讯项编码不能为空!" ) return end if ( value == nil ) then lua.Warning( strLuaDEID, debug.getinfo(1), "PLC传入的设备状态值为 nil! " ) return end lua.Debug( strLuaDEID, debug.getinfo(1), "PLC", input_datajson ) -- 获取线体编码 line_seg_code -- comm_code 的格式是 1001_XXXX 前面是线体编码 local seg = {} local nCount seg = lua.split( comm_code, '_' ) nCount = #seg if ( nCount ~= 2 ) then lua.Warning( strLuaDEID, debug.getinfo(1), "PLC传入的设备通讯项编码格式不正确! "..comm_code ) return end local line_seg_code = seg[1] -- 线体编码 -- step4: 通过OIDeviceCommS请求获取设备目前的托盘号 cntr_code local cntr_code = wms_dev.ReadS7PLCCommsData( strLuaDEID, device_code, line_seg_code.."_CNTR" ) lua.Debug( strLuaDEID, debug.getinfo(1), "cntr_code", cntr_code ) if ( type(cntr_code) ~= "string" ) then lua.Error( strLuaDEID, debug.getinfo(1), "调用OIDeviceCommS接口ReadData返回的容器编码格式不对,必须是字符串类型!" ) end -- step5: 解析返回的容器号,并且进行容器号合格判断 (容器编码TP1/TP2 开头后面7位数字) local strHeader -- 容器号的前3位字符串 nRet, strHeader = XX_CheckCNTRCode( cntr_code ) if ( nRet ~= 0 ) then -- 输出 LED 错误信息 这块代码还需要完善 -- ??? lua.Error( strLuaDEID, debug.getinfo(1), strHeader ) end -- step6: 判断容器是否存在? 不存在创建 if ( wms_cntr.Exist( strLuaDEID, cntr_code ) == false ) then -- 【容器】不存在要先创建【容器】 local container = m3.AllocObject(strLuaDEID,"Container") container.code = cntr_code nRet, strRetInfo = m3.CreateDataObj(strLuaDEID, container) if ( nRet ~= 0 ) then lua.Error( strLuaDEID, debug.getinfo(1), '创建【容器】对象失败!'..strRetInfo ) end end -- step7: 通过信号源所在的线体编号确定是 线体目前是做开始入库还是开始出库,或是开始入库到线体目标位置? -- 根据 设备编号 + 通讯项目编码 获取货位号 及 货位的出入口属性 local dev_comms_ext nRet, dev_comms_ext = wms_dev.GetDeviceCommSExtInfo ( device_code, comm_code ) if ( nRet ~= 0 ) then lua.Error( strLuaDEID, debug.getinfo(1), dev_comms_ext ) end local pos_type = lua.Get_StrAttrValue( dev_comms_ext.pos_type ) local str_loc_code = lua.Get_StrAttrValue( dev_comms_ext.loc_code ) if ( pos_type == nil or pos_type == '' ) then lua.Error( strLuaDEID, debug.getinfo(1), "设备通讯项'"..comm_code.."'的设置不完整,需要设置该通讯项对应线体处所位置的出入口类型!") end if ( str_loc_code == nil or str_loc_code == '' ) then lua.Error( strLuaDEID, debug.getinfo(1), "设备通讯项'"..comm_code.."'的设置不完整,需要设置该通讯项对应线体所处的货位编码!") end -- step8: 光电有框处理,根据线体所属的出入口类型确定作业类型(入库还是出库) if ( pos_type == '入库线入口' ) then -- 创建入库作业 create_warehousing_operation( strLuaDEID, device_code, str_loc_code, cntr_code ) elseif ( pos_type == '出库线入口' ) then -- 创建出库作业(暂时不需要) elseif ( pos_type == '出库线出口' ) then -- 创建出库作业(暂时不需要) -- 根据托盘号获取任务编号 (完整的任务号无法保存到设备里) local task = XX_GetTaskByCNTR( strLuaDEID, device_code, cntr_code ) if ( task ~= nil ) then -- 设置动作码和动作名称 local action_code = wms_base.Get_nConst(strLuaDEID , "输送线-出库口到货") -- 11 local action = "输送线-出库口到货" -- 把线体编码 line_seg_code 作为data保存到 设备队列 Create_MQAction( strLuaDEID, device_code, task.code, action_code, action, line_seg_code ) else lua.Error( strLuaDEID, debug.getinfo(1), "无法获取任务号! device_code = "..device_code.." cntr_code = "..cntr_code ) end elseif ( pos_type == '入库线出口' ) then -- 新增设备动作队列 -- 根据托盘号获取任务编号 (完整的任务号无法保存到设备里) local task = XX_GetTaskByCNTR( strLuaDEID, device_code, cntr_code ) if ( task ~= nil ) then -- 设置动作码和动作名称 local action_code = wms_base.Get_nConst(strLuaDEID , "输送线-入库口到货") -- 10 local action = "输送线-入库口到货" -- 把线体编码 line_seg_code 作为data保存到 设备队列 Create_MQAction( strLuaDEID, device_code, task.code, action_code, action, line_seg_code ) else lua.Error( strLuaDEID, debug.getinfo(1), "无法获取任务号! device_code = "..device_code.." cntr_code = "..cntr_code ) end else lua.Error( strLuaDEID, debug.getinfo(1), "设备通讯项'"..comm_code.."'的出入口类型设置不正确!") end end